function get_subs(cmds) {
    var subs = {}
    for (var i = 0; i < cmds.length; i++) {
        if (/\w+\:/g.test(cmds[i])) subs[cmds[i].replace(/\:/, '')] = i;
    }
    return subs;
}


function assemblerInterpreter(program) {
    var vars = {};
    var isvar = (x) => Object.keys(vars).includes(x)
    var cmds = program.split('\n').map(v => v.trimLeft().replace(/\;.*/g, '').trim());
    var end = cmds.findIndex(v => v === 'end');
    var subs = get_subs(cmds)
    var cmps = {}; //store compare results
    var ret_lines = [];
    var debug = 0;
    var MAX = 500;
    for (var i = 0; i < cmds.length; i++) {
        debug++;
        if (debug > MAX) { console.log('Something wrong,infinity loop maybe.'); break; }
        var cmd = cmds[i].split(/\s+/g)[0];
        var args = cmds[i].replace(/^\w+\s+/, '').split(/,\s+/g);
        var [x, y] = args.slice(0, 2)
        switch (cmd) {
            case 'mov':
                vars[x] = isvar(y) ? vars[y] : +y;
                break;
            case 'inc':
                vars[x]++;
                break;
            case 'dec':
                vars[x]--;
                break;
            case 'add':
                vars[x] += isvar(y) ? vars[y] : +y;
                break;
            case 'sub':
                vars[x] -= isvar(y) ? vars[y] : +y;
                break;
            case 'mul':
                vars[x] *= isvar(y) ? vars[y] : +y;
                break;
            case 'div':
                vars[x] = parseInt(vars[x] / (isvar(y) ? vars[y] : +y));
                break;
            case 'call':
                ret_lines.push(i);
                i = subs[x];
                break;
            case 'cmp':
                cmps['jne'] = (vars[x] != (isvar(y) ? vars[y] : +y))
                cmps['je'] = (vars[x] == (isvar(y) ? vars[y] : +y))
                cmps['jge'] = (vars[x] >= (isvar(y) ? vars[y] : +y))
                cmps['jg'] = (vars[x] > (isvar(y) ? vars[y] : +y))
                cmps['jle'] = (vars[x] <= (isvar(y) ? vars[y] : +y))
                cmps['jl'] = (vars[x] < (isvar(y) ? vars[y] : +y))
                break;
            case 'jmp':
                //ret_lines.push(i);//?
                i = subs[x];
                break;
            case 'jne':
                if (cmps['jne']) i = subs[x];
                break;
            case 'je':
                if (cmps['je']) i = subs[x];
                break;
            case 'jge':
                if (cmps['jge']) i = subs[x];
                break;
            case 'jg':
                if (cmps['jg']) i = subs[x];
                break;
            case 'jle':
                if (cmps['jle']) i = subs[x];
                break;
            case 'jl':
                if (cmps['jl']) i = subs[x];
                break;
            case 'msg':
                if (cmds[i + 1] == 'end' || cmds[i + 1] == 'ret') {
                    var s = cmds[i].replace(/^\w+\s+/, '');
                    var arr = s.replace(/,(?=([^\']*\'[^\']*\')*[^\']*$)/g, '#').split('#')
                    return arr.map(v => /\'(.*)\'/g.test(v) ? RegExp.$1 : vars[v.trim()]).join('');
                }
                return -1;
            case 'ret':
                i = ret_lines.pop();
                break;
            case 'end':
                break;
        }
        //console.log(cmd, args)
    }
}
var program_mod = `mov   a, 11           ; value1
mov   b, 3            ; value2
call  mod_func
msg   'mod(', a, ', ', b, ') = ', d        ; output
end

; Mod function
mod_func:
    mov   c, a        ; temp1
    div   c, b
    mul   c, b
    mov   d, a        ; temp2
    sub   d, c
    ret`
console.log(assemblerInterpreter(program_mod))